home *** CD-ROM | disk | FTP | other *** search
/ OpenGL Superbible (2nd Edition) / OpenGL SuperBible e2.iso / tools / GLUT-3.7 / PROGS / DEMOS / SMOOTH / SMOOTH.C < prev    next >
Encoding:
C/C++ Source or Header  |  1998-08-12  |  10.8 KB  |  465 lines

  1. /*  
  2.     smooth.c
  3.     Nate Robins, 1997
  4.  
  5.     Model viewer program.  Excercises the glm library.
  6.  */
  7.  
  8. #include <math.h>
  9. #include <stdlib.h>
  10. #include <stdio.h>
  11. #include <assert.h>
  12. #include <stdarg.h>
  13. #include <GL/glut.h>
  14. #include "tb.h"
  15. #include "glm.h"
  16.  
  17. GLuint     model_list = 0;        /* display list for object */
  18. char*      model_file = NULL;        /* name of the obect file */
  19. GLboolean  facet_normal = GL_FALSE;    /* draw with facet normal? */
  20. GLMmodel*  model;
  21. GLfloat    smoothing_angle = 90.0;    /* smoothing angle */
  22. GLfloat    scale;            /* scaling factor */
  23. GLdouble   pan_x = 0.0;
  24. GLdouble   pan_y = 0.0;
  25. GLdouble   pan_z = 0.0;
  26. GLint      mouse_state = -1;
  27. GLint      mouse_button = -1;
  28. GLboolean  bounding_box = GL_FALSE;
  29. GLboolean  performance = GL_FALSE;
  30. GLboolean  stats = GL_FALSE;
  31. GLfloat    weld_distance = 0.00001;
  32. GLuint     material_mode = 0;
  33.  
  34.  
  35. /* text: general purpose text routine.  draws a string according to
  36.  * format in a stroke font at x, y after scaling it by the scale
  37.  * specified (scale is in window-space (lower-left origin) pixels).  
  38.  *
  39.  * x      - position in x (in window-space)
  40.  * y      - position in y (in window-space)
  41.  * scale  - scale in pixels
  42.  * format - as in printf()
  43.  */
  44. void 
  45. text(GLuint x, GLuint y, GLfloat scale, char* format, ...)
  46. {
  47.   va_list args;
  48.   char buffer[255], *p;
  49.   GLfloat font_scale = 119.05 + 33.33;
  50.  
  51.   va_start(args, format);
  52.   vsprintf(buffer, format, args);
  53.   va_end(args);
  54.  
  55.   glMatrixMode(GL_PROJECTION);
  56.   glPushMatrix();
  57.   glLoadIdentity();
  58.   gluOrtho2D(0, glutGet(GLUT_WINDOW_WIDTH), 0, glutGet(GLUT_WINDOW_HEIGHT));
  59.  
  60.   glMatrixMode(GL_MODELVIEW);
  61.   glPushMatrix();
  62.   glLoadIdentity();
  63.  
  64.   glPushAttrib(GL_ENABLE_BIT);
  65.   glDisable(GL_LIGHTING);
  66.   glDisable(GL_TEXTURE_2D);
  67.   glDisable(GL_DEPTH_TEST);
  68.   glTranslatef(x, y, 0.0);
  69.  
  70.   glScalef(scale/font_scale, scale/font_scale, scale/font_scale);
  71.  
  72.   for(p = buffer; *p; p++)
  73.     glutStrokeCharacter(GLUT_STROKE_ROMAN, *p);
  74.   
  75.   glPopAttrib();
  76.  
  77.   glPopMatrix();
  78.   glMatrixMode(GL_PROJECTION);
  79.   glPopMatrix();
  80.   glMatrixMode(GL_MODELVIEW);
  81. }
  82.  
  83. void
  84. lists(void)
  85. {
  86.   GLfloat ambient[] = { 0.2, 0.2, 0.2, 1.0 };
  87.   GLfloat diffuse[] = { 0.8, 0.8, 0.8, 1.0 };
  88.   GLfloat specular[] = { 0.0, 0.0, 0.0, 1.0 };
  89.   GLfloat shininess = 65.0;
  90.  
  91.   if (model_list)
  92.     glDeleteLists(model_list, 1);
  93.  
  94.   glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, ambient);
  95.   glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, diffuse);
  96.   glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, specular);
  97.   glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, shininess);
  98.  
  99.   /* generate a list */
  100.   if (material_mode == 0) { 
  101.     if (facet_normal)
  102.       model_list = glmList(model, GLM_FLAT);
  103.     else
  104.       model_list = glmList(model, GLM_SMOOTH);
  105.   } else if (material_mode == 1) {
  106.     if (facet_normal)
  107.       model_list = glmList(model, GLM_FLAT | GLM_COLOR);
  108.     else
  109.       model_list = glmList(model, GLM_SMOOTH | GLM_COLOR);
  110.   } else if (material_mode == 2) {
  111.     if (facet_normal)
  112.       model_list = glmList(model, GLM_FLAT | GLM_MATERIAL);
  113.     else
  114.       model_list = glmList(model, GLM_SMOOTH | GLM_MATERIAL);
  115.   }
  116. }
  117.  
  118. void
  119. init(void)
  120. {
  121.   tbInit(GLUT_MIDDLE_BUTTON);
  122.   
  123.   /* read in the model */
  124.   model = glmReadOBJ(model_file);
  125.   scale = glmUnitize(model);
  126.   glmFacetNormals(model);
  127.   glmVertexNormals(model, smoothing_angle);
  128.  
  129.   if (model->nummaterials > 0)
  130.       material_mode = 2;
  131.  
  132.   /* create new display lists */
  133.   lists();
  134.  
  135.   glEnable(GL_LIGHTING);
  136.   glEnable(GL_LIGHT0);
  137.   glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE);
  138.  
  139.   glEnable(GL_DEPTH_TEST);
  140.  
  141.   glEnable(GL_CULL_FACE);
  142. }
  143.  
  144. void
  145. reshape(int width, int height)
  146. {
  147.   tbReshape(width, height);
  148.  
  149.   glViewport(0, 0, width, height);
  150.   
  151.   glMatrixMode(GL_PROJECTION);
  152.   glLoadIdentity();
  153.   gluPerspective(60.0, (GLfloat)height / (GLfloat)width, 1.0, 128.0);
  154.   glMatrixMode(GL_MODELVIEW);
  155.   glLoadIdentity();
  156.   glTranslatef(0.0, 0.0, -3.0);
  157. }
  158.  
  159. void
  160. display(void)
  161. {
  162.   static int start, end, last;
  163.  
  164.   start = glutGet(GLUT_ELAPSED_TIME);
  165.  
  166.   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  167.  
  168.   if (performance) {
  169.     glColor3f(1.0, 1.0, 1.0);
  170.     text(5, 5, 20, "%.2f fps", 1.0 / ((end - last) / 1000.0));
  171.     last = start;
  172.   }
  173.  
  174.   glPushMatrix();
  175.  
  176.   glTranslatef(pan_x, pan_y, 0.0);
  177.  
  178.   tbMatrix();
  179.  
  180.   glEnable(GL_LIGHTING);
  181.   glEnable(GL_COLOR_MATERIAL);
  182.   glColor3f(0.5, 0.5, 0.5);
  183.   glCallList(model_list);
  184.  
  185.   if (bounding_box) {
  186.     glEnable(GL_BLEND);
  187.     glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
  188.     glEnable(GL_CULL_FACE);
  189.     glColor4f(1.0, 0.0, 0.0, 0.25);
  190.     glutSolidCube(2.0);
  191.   }
  192.  
  193.   glPopMatrix();
  194.  
  195.   if (stats) {
  196.     glColor3f(1.0, 1.0, 1.0);
  197.     text(5, glutGet(GLUT_WINDOW_HEIGHT) - (5+20*1), 20, "%s", 
  198.      model->pathname);
  199.     text(5, glutGet(GLUT_WINDOW_HEIGHT) - (5+20*2), 20, "%d vertices", 
  200.      model->numvertices);
  201.     text(5, glutGet(GLUT_WINDOW_HEIGHT) - (5+20*3), 20, "%d triangles", 
  202.      model->numtriangles);
  203.     text(5, glutGet(GLUT_WINDOW_HEIGHT) - (5+20*4), 20, "%d normals", 
  204.      model->numnormals);
  205.     text(5, glutGet(GLUT_WINDOW_HEIGHT) - (5+20*5), 20, "%d texcoords", 
  206.      model->numtexcoords);
  207.     text(5, glutGet(GLUT_WINDOW_HEIGHT) - (5+20*6), 20, "%d groups", 
  208.      model->numgroups);
  209.     text(5, glutGet(GLUT_WINDOW_HEIGHT) - (5+20*7), 20, "%d materials", 
  210.      model->nummaterials);
  211.   }
  212.  
  213.   glutSwapBuffers();
  214.  
  215.   end = glutGet(GLUT_ELAPSED_TIME);
  216. }
  217.  
  218. /* ARGSUSED1 */
  219. void
  220. keyboard(unsigned char key, int x, int y)
  221. {
  222.   GLint params[2];
  223.  
  224.   switch (key) {
  225.   case 'h':
  226.     printf("help\n\n");
  227.     printf("w            -  Toggle wireframe/filled\n");
  228.     printf("c            -  Toggle culling\n");
  229.     printf("n            -  Toggle facet/smooth normal\n");
  230.     printf("b            -  Toggle bounding box\n");
  231.     printf("r            -  Reverse polygon winding\n");
  232.     printf("m            -  Toggle color/material/none mode\n");
  233.     printf("p            -  Toggle performance indicator\n");
  234.     printf("s/S          -  Scale model smaller/larger\n");
  235.     printf("t            -  Show model stats\n");
  236.     printf("o            -  Weld vertices in model\n");
  237.     printf("+/-          -  Increase/decrease smoothing angle\n");
  238.     printf("W            -  Write model to file (out.obj)\n");
  239.     printf("q/escape     -  Quit\n\n");
  240.     break;
  241.  
  242.   case 't':
  243.     stats = !stats;
  244.     break;
  245.  
  246.   case 'p':
  247.     performance = !performance;
  248.     break;
  249.  
  250.   case 'm':
  251.     material_mode++;
  252.     if (material_mode > 2)
  253.       material_mode = 0;
  254.     printf("material_mode = %d\n", material_mode);
  255.     lists();
  256.     break;
  257.  
  258.   case 'd':
  259.     glmDelete(model);
  260.     init();
  261.     lists();
  262.     break;
  263.  
  264.   case 'w':
  265.     glGetIntegerv(GL_POLYGON_MODE, params);
  266.     if (params[0] == GL_FILL)
  267.       glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
  268.     else
  269.       glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
  270.     break;
  271.  
  272.   case 'c':
  273.     if (glIsEnabled(GL_CULL_FACE))
  274.       glDisable(GL_CULL_FACE);
  275.     else
  276.       glEnable(GL_CULL_FACE);
  277.     break;
  278.  
  279.   case 'b':
  280.     bounding_box = !bounding_box;
  281.     break;
  282.  
  283.   case 'n':
  284.     facet_normal = !facet_normal;
  285.     lists();
  286.     break;
  287.  
  288.   case 'r':
  289.     glmReverseWinding(model);
  290.     lists();
  291.     break;
  292.  
  293.   case 's':
  294.     glmScale(model, 0.8);
  295.     lists();
  296.     break;
  297.  
  298.   case 'S':
  299.     glmScale(model, 1.25);
  300.     lists();
  301.     break;
  302.  
  303.   case 'o':
  304.     glmWeld(model, weld_distance);
  305.     glmVertexNormals(model, smoothing_angle);
  306.     lists();
  307.     break;
  308.  
  309.   case 'O':
  310.     weld_distance += 0.01;
  311.     printf("Weld distance: %.2f\n", weld_distance);
  312.     glmWeld(model, weld_distance);
  313.     glmFacetNormals(model);
  314.     glmVertexNormals(model, smoothing_angle);
  315.     lists();
  316.     break;
  317.  
  318.   case '-':
  319.     smoothing_angle -= 1.0;
  320.     printf("Smoothing angle: %.1f\n", smoothing_angle);
  321.     glmVertexNormals(model, smoothing_angle);
  322.     lists();
  323.     break;
  324.     
  325.   case '+':
  326.     smoothing_angle += 1.0;
  327.     printf("Smoothing angle: %.1f\n", smoothing_angle);
  328.     glmVertexNormals(model, smoothing_angle);
  329.     lists();
  330.     break;
  331.     
  332.   case 'W':
  333.     glmScale(model, 1.0/scale);
  334.     glmWriteOBJ(model, "out.obj", GLM_SMOOTH | GLM_MATERIAL);
  335.     break;
  336.  
  337.   case 'R':
  338.     {
  339.       GLuint i;
  340.       GLfloat swap;
  341.       for (i = 1; i <= model->numvertices; i++) {
  342.     swap = model->vertices[3 * i + 1];
  343.     model->vertices[3 * i + 1] = model->vertices[3 * i + 2];
  344.     model->vertices[3 * i + 2] = -swap;
  345.       }
  346.       glmFacetNormals(model);
  347.       lists();
  348.       break;
  349.     }
  350.  
  351.   case 'q':
  352.   case 27:
  353.     exit(0);
  354.     break;
  355.   }
  356.  
  357.   glutPostRedisplay();
  358. }
  359.  
  360. void
  361. menu(int item)
  362. {
  363.     keyboard((unsigned char)item, 0, 0);
  364. }
  365.  
  366. void
  367. mouse(int button, int state, int x, int y)
  368. {
  369.   GLdouble model[4*4];
  370.   GLdouble proj[4*4];
  371.   GLint view[4];
  372.  
  373.   tbMouse(button, state, x, y);
  374.  
  375.   mouse_state = state;
  376.   mouse_button = button;
  377.  
  378.   if (state == GLUT_DOWN && button == GLUT_LEFT_BUTTON) {
  379.     glGetDoublev(GL_MODELVIEW_MATRIX, model);
  380.     glGetDoublev(GL_PROJECTION_MATRIX, proj);
  381.     glGetIntegerv(GL_VIEWPORT, view);
  382.     gluProject((GLdouble)x, (GLdouble)y, 0.0,
  383.          model, proj, view,
  384.          &pan_x, &pan_y, &pan_z);
  385.     gluUnProject((GLdouble)x, (GLdouble)y, pan_z,
  386.          model, proj, view,
  387.          &pan_x, &pan_y, &pan_z);
  388.     pan_y = -pan_y;
  389.   }
  390.  
  391.   glutPostRedisplay();
  392. }
  393.  
  394. void
  395. motion(int x, int y)
  396. {
  397.   GLdouble model[4*4];
  398.   GLdouble proj[4*4];
  399.   GLint view[4];
  400.  
  401.   tbMotion(x, y);
  402.  
  403.   if (mouse_state == GLUT_DOWN && mouse_button == GLUT_LEFT_BUTTON) {
  404.     glGetDoublev(GL_MODELVIEW_MATRIX, model);
  405.     glGetDoublev(GL_PROJECTION_MATRIX, proj);
  406.     glGetIntegerv(GL_VIEWPORT, view);
  407.     gluProject((GLdouble)x, (GLdouble)y, 0.0,
  408.          model, proj, view,
  409.          &pan_x, &pan_y, &pan_z);
  410.     gluUnProject((GLdouble)x, (GLdouble)y, pan_z,
  411.          model, proj, view,
  412.          &pan_x, &pan_y, &pan_z);
  413.     pan_y = -pan_y;
  414.   }
  415.  
  416.   glutPostRedisplay();
  417. }
  418.  
  419. int
  420. main(int argc, char** argv)
  421. {
  422.   glutInitWindowSize(512, 512);
  423.   glutInit(&argc, argv);
  424.  
  425.   model_file = argv[1];
  426.   if (!model_file) {
  427.     fprintf(stderr, "usage: smooth model_file.obj\n");
  428.     exit(1);
  429.   }
  430.  
  431.   glutInitDisplayMode(GLUT_RGB | GLUT_DEPTH | GLUT_DOUBLE);
  432.   glutCreateWindow("smooth");
  433.   
  434.   glutReshapeFunc(reshape);
  435.   glutDisplayFunc(display);
  436.   glutKeyboardFunc(keyboard);
  437.   glutMouseFunc(mouse);
  438.   glutMotionFunc(motion);
  439.   glutCreateMenu(menu);
  440.   glutAddMenuEntry("Smooth", 0);
  441.   glutAddMenuEntry("", 0);
  442.   glutAddMenuEntry("[w] Toggle wireframe/filled", 'w');
  443.   glutAddMenuEntry("[c] Toggle culling on/off", 'c');
  444.   glutAddMenuEntry("[n] Toggle facet/smooth normals", 'n');
  445.   glutAddMenuEntry("[b] Toggle bounding box on/off", 'b');
  446.   glutAddMenuEntry("[r] Reverse polygon winding", 'r');
  447.   glutAddMenuEntry("[m] Toggle color/material/none mode", 'm');
  448.   glutAddMenuEntry("[s] Scale model smaller", 's');
  449.   glutAddMenuEntry("[S] Scale model larger", 'S');
  450.   glutAddMenuEntry("[p] Toggle performance indicator", 'c');
  451.   glutAddMenuEntry("[o] Weld redundant vertices", 'c');
  452.   glutAddMenuEntry("[t] Show model stats", 'c');
  453.   glutAddMenuEntry("[+] Increase smoothing angle", '+');
  454.   glutAddMenuEntry("[-] Decrease smoothing angle", '-');
  455.   glutAddMenuEntry("[W] Write model to file (out.obj)", 'W');
  456.   glutAddMenuEntry("", 0);
  457.   glutAddMenuEntry("[q] Quit", 27);
  458.   glutAttachMenu(GLUT_RIGHT_BUTTON);
  459.   
  460.   init();
  461.   
  462.   glutMainLoop();
  463.   return 0;
  464. }
  465.